package com.lcf.framework.utils;

import com.lcf.base.exception.SysException;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES
 *
 * @author lcf
 */
public class AesUtils {
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static final String TRANSFORMATION_ECB = "AES/ECB/PKCS5Padding";
    private static final int IV_LENGTH = 16;

    /**
     * 加密（自动生成随机 IV）
     *
     * @param plaintext 明文
     * @param secretKey 密钥 (16/24/32 字节)
     */
    public static String encrypt(String plaintext, String secretKey) {
        try {
            checkKey(secretKey);
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), ALGORITHM);

            // 生成随机 IV
            byte[] ivBytes = new byte[IV_LENGTH];
            new SecureRandom().nextBytes(ivBytes);
            IvParameterSpec iv = new IvParameterSpec(ivBytes);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
            byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

            // 拼接 IV + 密文，并编码为 Base64
            byte[] combined = new byte[ivBytes.length + encryptedBytes.length];
            System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length);
            System.arraycopy(encryptedBytes, 0, combined, ivBytes.length, encryptedBytes.length);
            return Base64.getUrlEncoder().encodeToString(combined);
        } catch (Exception e) {
            throw new SysException(e);
        }
    }

    /**
     * 解密（从密文中提取 IV）
     *
     * @param ciphertext 密文（Base64 编码）
     * @param secretKey  密钥
     */
    public static String decrypt(String ciphertext, String secretKey) {
        try {
            checkKey(secretKey);
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), ALGORITHM);

            // 解码并分离 IV 和密文
            byte[] combined = Base64.getUrlDecoder().decode(ciphertext);
            byte[] ivBytes = new byte[IV_LENGTH];
            System.arraycopy(combined, 0, ivBytes, 0, ivBytes.length);
            IvParameterSpec iv = new IvParameterSpec(ivBytes);

            byte[] encryptedBytes = new byte[combined.length - ivBytes.length];
            System.arraycopy(combined, ivBytes.length, encryptedBytes, 0, encryptedBytes.length);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new SysException(e);
        }
    }

    /**
     * 加密（ECB 模式无需 IV）
     */
    public static String encryptEcb(String plaintext, String secretKey) {
        try {
            checkKey(secretKey);
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), ALGORITHM);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

            return Base64.getUrlEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new SysException(e);
        }
    }

    /**
     * 解密（ECB 模式无需 IV）
     */
    public static String decryptEcb(String ciphertext, String secretKey) {
        try {
            checkKey(secretKey);
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), ALGORITHM);

            byte[] encryptedBytes = Base64.getUrlDecoder().decode(ciphertext);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new SysException(e);
        }
    }

    /**
     * 密钥合法性检查
     */
    private static void checkKey(String key) {
        if (StringUtils.isBlank(key)) {
            throw new SysException("密钥为空");
        }
        int len = key.length();
        if (len != 16 && len != 24 && len != 32) {
            throw new SysException("密钥长度必须为 16/24/32 字节，当前长度: " + len);
        }
    }

    // 测试
    public static void main(String[] args) {
        // 从配置读取密钥，禁止硬编码！
        String secretKey = "sIsA32ByteKeyFor1AE256Encryption";

        String plaintext = "123";
        String encrypted = encrypt(plaintext, secretKey);
        System.out.println("加密结果: " + encrypted);

        String decrypted = decrypt(encrypted, secretKey);
        System.out.println("解密结果: " + decrypted);
    }
}
